{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Electronic structure"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introduction \n",
    "\n",
    "The molecular Hamiltonian is \n",
    "\n",
    "$$\n",
    "\\mathcal{H} = - \\sum_I \\frac{\\nabla_{R_I}^2}{M_I} - \\sum_i \\frac{\\nabla_{r_i}^2}{m_e} - \\sum_I\\sum_i  \\frac{Z_I e^2}{|R_I-r_i|} + \\sum_i \\sum_{j>i} \\frac{e^2}{|r_i-r_j|} + \\sum_I\\sum_{J>I} \\frac{Z_I Z_J e^2}{|R_I-R_J|}\n",
    "$$\n",
    "\n",
    "Because the nuclei are much heavier than the electrons they do not move on the same time scale and therefore, the behavior of nuclei and electrons can be decoupled. This is the Born-Oppenheimer approximation.\n",
    "\n",
    "Therefore, one can first tackle the electronic problem with nuclear coordinate entering only as parameters. The energy levels of the electrons in the molecule can be found by solving the non-relativistic time independent Schroedinger equation,\n",
    "\n",
    "$$\n",
    "\\mathcal{H}_{\\text{el}} |\\Psi_{n}\\rangle = E_{n} |\\Psi_{n}\\rangle\n",
    "$$\n",
    "\n",
    "where \n",
    "\n",
    "$$\n",
    "\\mathcal{H}_{\\text{el}} = - \\sum_i \\frac{\\nabla_{r_i}^2}{m_e} - \\sum_I\\sum_i  \\frac{Z_I e^2}{|R_I-r_i|} + \\sum_i \\sum_{j>i} \\frac{e^2}{|r_i-r_j|}.\n",
    "$$\n",
    "\n",
    "In particular the ground state energy is given by:\n",
    "$$\n",
    "E_0 = \\frac{\\langle \\Psi_0 | H_{\\text{el}} | \\Psi_0 \\rangle}{\\langle \\Psi_0 | \\Psi_0 \\rangle}\n",
    "$$\n",
    "where $\\Psi_0$ is the ground state of the system. \n",
    "\n",
    "However, the dimensionality of this problem grows exponentially with the number of degrees of freedom. To tackle this issue we would like to prepare $\\Psi_0$ on a quantum computer and measure the Hamiltonian expectation value (or $E_0$) directly. \n",
    "\n",
    "So how do we do that concretely? \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The Hartree-Fock initial state \n",
    "\n",
    "A good starting point for solving this problem is the Hartree-Fock (HF) method. This method approximates a N-body problem into N one-body problems where each electron evolves in the mean-field of the others. Classically solving the HF equations is efficient and leads to the exact exchange energy but does not include any electron correlation. Therefore, it is usually a good starting point to start adding correlation. \n",
    "\n",
    "The Hamiltonian can then be re-expressed in the basis of the solutions of the HF method, also called Molecular Orbitals (MOs):\n",
    "\n",
    "$$\n",
    "\\hat{H}_{elec}=\\sum_{pq} h_{pq} \\hat{a}^{\\dagger}_p \\hat{a}_q + \n",
    "\\frac{1}{2} \\sum_{pqrs} h_{pqrs}  \\hat{a}^{\\dagger}_p \\hat{a}^{\\dagger}_q \\hat{a}_r  \\hat{a}_s\n",
    "$$\n",
    "with the 1-body integrals\n",
    "$$\n",
    "h_{pq} = \\int \\phi^*_p(r) \\left( -\\frac{1}{2} \\nabla^2 - \\sum_{I} \\frac{Z_I}{R_I- r} \\right)   \\phi_q(r)dr\n",
    "$$\n",
    "and 2-body integrals\n",
    "$$\n",
    "h_{pqrs} = \\int \\frac{\\phi^*_p(r_1)  \\phi^*_q(r_2) \\phi_r(r_2)  \\phi_s(r_1)}{|r_1-r_2|}dr_1dr_2.\n",
    "$$\n",
    "\n",
    "The MOs ($\\phi_u$) can be occupied or virtual (unoccupied). One MO can contain 2 electrons. However, in what follows we actually work with Spin Orbitals which are associated with a spin up ($\\alpha$) of spin down ($\\beta$) electron. Thus Spin Orbitals can contain one electron or be unoccupied. \n",
    "\n",
    "We now show how to concretely realise these steps with Qiskit."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Qiskit is interfaced with different classical codes which are able to find the HF solutions. Interfacing between Qiskit and the following codes is already available:\n",
    "* Gaussian\n",
    "* Psi4\n",
    "* PyQuante\n",
    "* PySCF\n",
    "\n",
    "In the following we set up a PySCF driver, for the hydrogen molecule at equilibrium bond length (0.735 angstrom) in the singlet state and with no charge. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Couldn't find cython becke routine\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/manoel/opt/anaconda3/envs/Qiskitenv/lib/python3.8/site-packages/pyscf/lib/misc.py:46: H5pyDeprecationWarning: Using default_file_mode other than 'r' is deprecated. Pass the mode to h5py.File() instead.\n",
      "  h5py.get_config().default_file_mode = 'a'\n"
     ]
    }
   ],
   "source": [
    "from qiskit_nature.drivers import UnitsType, Molecule\n",
    "from qiskit_nature.drivers.second_quantization import (\n",
    "    ElectronicStructureDriverType,\n",
    "    ElectronicStructureMoleculeDriver,\n",
    ")\n",
    "\n",
    "molecule = Molecule(\n",
    "    geometry=[[\"H\", [0.0, 0.0, 0.0]], [\"H\", [0.0, 0.0, 0.735]]], charge=0, multiplicity=1\n",
    ")\n",
    "driver = ElectronicStructureMoleculeDriver(\n",
    "    molecule, basis=\"sto3g\", driver_type=ElectronicStructureDriverType.PYSCF\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For further information about the drivers see https://qiskit.org/documentation/nature/apidocs/qiskit_nature.drivers.second_quantization.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The mapping from fermions to qubits \n",
    "\n",
    "<img src=\"aux_files/jw_mapping.png\" width=\"500\">\n",
    "\n",
    "The Hamiltonian given in the previous section is expressed in terms of fermionic operators. To encode the problem into the state of a quantum computer, these operators must be mapped to spin operators (indeed the qubits follow spin statistics). \n",
    "\n",
    "There exist different mapping types with different properties. Qiskit already supports the following mappings:\n",
    "* The Jordan-Wigner 'jordan_wigner' mapping (über das paulische äquivalenzverbot. In The Collected Works of Eugene Paul Wigner (pp. 109-129). Springer, Berlin, Heidelberg (1993)).\n",
    "* The Parity 'parity' (The Journal of chemical physics, 137(22), 224109 (2012))\n",
    "* The Bravyi-Kitaev 'bravyi_kitaev' (Annals of Physics, 298(1), 210-226 (2002))\n",
    "\n",
    "The Jordan-Wigner mapping is particularly interesting as it maps each Spin Orbital to a qubit (as shown on the Figure above). \n",
    "\n",
    "Here we set up the Electronic Structure Problem to generate the Second quantized operator and a qubit converter that will map it to a qubit operator."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit_nature.problems.second_quantization import ElectronicStructureProblem\n",
    "from qiskit_nature.converters.second_quantization import QubitConverter\n",
    "from qiskit_nature.mappers.second_quantization import JordanWignerMapper, ParityMapper"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  +-+- * (0.18093119978423117+0j)\n",
      "+ +--+ * (-0.18093119978423128+0j)\n",
      "+ -++- * (-0.18093119978423128+0j)\n",
      "+ -+-+ * (0.18093119978423136+0j)\n",
      "+ IIIN * (-0.4718960072811401+0j)\n",
      "+ IINI * (-1.2563390730032502+0j)\n",
      "+ IINN * (0.4836505304710652+0j)\n",
      "+ INII * (-0.4718960072811401+0j)\n",
      "+ ININ * (0.6985737227320179+0j)\n",
      "+ INNI * (0.6645817302552963+0j)\n",
      "+ NIII * (-1.2563390730032502+0j)\n",
      "+ NIIN * (0.6645817302552963+0j)\n",
      "+ NINI * (0.6757101548035165+0j)\n",
      "+ NNII * (0.4836505304710652+0j)\n"
     ]
    }
   ],
   "source": [
    "es_problem = ElectronicStructureProblem(driver)\n",
    "second_q_op = es_problem.second_q_ops()\n",
    "print(second_q_op[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we now transform this Hamiltonian for the given driver defined above we get our qubit operator:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-0.8105479805373259 * IIII\n",
      "- 0.2257534922240248 * ZIII\n",
      "+ 0.17218393261915566 * IZII\n",
      "+ 0.1209126326177663 * ZZII\n",
      "- 0.2257534922240248 * IIZI\n",
      "+ 0.17464343068300447 * ZIZI\n",
      "+ 0.16614543256382408 * IZZI\n",
      "+ 0.17218393261915566 * IIIZ\n",
      "+ 0.16614543256382408 * ZIIZ\n",
      "+ 0.16892753870087912 * IZIZ\n",
      "+ 0.1209126326177663 * IIZZ\n",
      "+ 0.04523279994605782 * XXXX\n",
      "+ 0.04523279994605782 * YYXX\n",
      "+ 0.04523279994605782 * XXYY\n",
      "+ 0.04523279994605782 * YYYY\n"
     ]
    }
   ],
   "source": [
    "qubit_converter = QubitConverter(mapper=JordanWignerMapper())\n",
    "qubit_op = qubit_converter.convert(second_q_op[0])\n",
    "print(qubit_op)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the minimal (STO-3G) basis set 4 qubits are required. We can reduce the number of qubits by using the Parity mapping, which allows for the removal of 2 qubits by exploiting known symmetries arising from the mapping. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(-1.052373245772858+5.551115123125783e-17j) * II\n",
      "+ (-0.39793742484318034+1.3877787807814457e-17j) * ZI\n",
      "+ (0.3979374248431804-2.7755575615628914e-17j) * IZ\n",
      "+ (-0.011280104256235449-1.3877787807814457e-17j) * ZZ\n",
      "+ (0.18093119978423114-3.469446951953614e-18j) * XX\n"
     ]
    }
   ],
   "source": [
    "qubit_converter = QubitConverter(mapper=ParityMapper(), two_qubit_reduction=True)\n",
    "qubit_op = qubit_converter.convert(second_q_op[0], num_particles=es_problem.num_particles)\n",
    "print(qubit_op)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This time only 2 qubits are needed. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that the Hamiltonian is ready, it can be used in a quantum algorithm to find information about the electronic structure of the corresponding molecule. Check out our tutorials on Ground State Calculation and Excited States Calculation to learn more about how to do that in Qiskit!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<h3>Version Information</h3><table><tr><th>Qiskit Software</th><th>Version</th></tr><tr><td><code>qiskit-terra</code></td><td>0.19.0.dev0+105cba3</td></tr><tr><td><code>qiskit-aer</code></td><td>0.9.0</td></tr><tr><td><code>qiskit-ignis</code></td><td>0.7.0.dev0+9201ed8</td></tr><tr><td><code>qiskit-nature</code></td><td>0.2.0</td></tr><tr><td><code>qiskit-finance</code></td><td>0.3.0</td></tr><tr><td><code>qiskit-optimization</code></td><td>0.3.0</td></tr><tr><td><code>qiskit-machine-learning</code></td><td>0.3.0</td></tr><tr><th>System information</th></tr><tr><td>Python</td><td>3.8.10 (default, May 19 2021, 11:01:55) \n",
       "[Clang 10.0.0 ]</td></tr><tr><td>OS</td><td>Darwin</td></tr><tr><td>CPUs</td><td>2</td></tr><tr><td>Memory (Gb)</td><td>12.0</td></tr><tr><td colspan='2'>Mon Jul 26 13:45:29 2021 EDT</td></tr></table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div style='width: 100%; background-color:#d5d9e0;padding-left: 10px; padding-bottom: 10px; padding-right: 10px; padding-top: 5px'><h3>This code is a part of Qiskit</h3><p>&copy; Copyright IBM 2017, 2021.</p><p>This code is licensed under the Apache License, Version 2.0. You may<br>obtain a copy of this license in the LICENSE.txt file in the root directory<br> of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.<p>Any modifications or derivative works of this code must retain this<br>copyright notice, and modified files need to carry a notice indicating<br>that they have been altered from the originals.</p></div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import qiskit.tools.jupyter\n",
    "\n",
    "%qiskit_version_table\n",
    "%qiskit_copyright"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
